package com.pipi.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pipi.dao.mapper.MyUserMapper;
import com.pipi.dao.pojo.Disk;
import com.pipi.entity.Result;
import com.pipi.entity.User;
import com.pipi.entity.healthData;
import com.pipi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author asus
 * @description 针对表【user(用户表)】的数据库操作Service实现
 * @createDate 2025-04-02 11:13:34
 */
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<MyUserMapper, User>
        implements UserService {

    @Autowired
    private MyUserMapper userMapper;


    @Override
    public Result addUser(User user) {
        if (StringUtils.isEmpty(user.getUserOpenid())) {
            throw new IllegalArgumentException("user_openid 不能为空");
        } else {
            //将userd的openid在已有用户表中是否存在，若存在则不进行添加
            if (userMapper.selectUserByOpenId(user.getUserOpenid()) == 1) {
                return Result.ok("用户已存在");
            } else {
                String userOpenid = user.getUserOpenid();
                String userName = user.getUserName();
                String avatarUrl = user.getAvatarUrl();
                Date createTime = new Date();
                userMapper.addUser(userOpenid, userName, avatarUrl, createTime);
                return Result.ok("注册成功");
            }
        }
    }

    @Override
    public Result updateUserInfo(User user) {
        //获取当前时间
        Date date = new Date();
        user.setCreateTime(date);
        user.setUpdateTime(date);
        System.out.println("服务层的user"+user);
        userMapper.updateUserInfo(user.getUserOpenid(), user.getUserName(), user.getUserAge(), user.getAvatarUrl(),user.getUpdateTime());
        userMapper.addUserHealthDataByOpenId(user.getUserOpenid(), user.getBloodPressure(), user.getBloodGlucose(), user.getBloodFat(),user.getCreateTime());
        return Result.ok();
    }

    @Override
    public List<User> getUserInfo() {
        List<User> users = userMapper.selectAll();
        return users;
    }

    @Override
    public User getUserInfoByOpenId(String userOpenid) {
        User user = userMapper.getUserInfoByOpenId(userOpenid);
        return user;
    }


    /**
     * 获取推荐菜单
     */
    @Override
    public List<Disk> getRecommendDisk(String openId) {
        // 1. 获取到所有用户数据
        List<User> users = userMapper.selectAll();
        System.out.println(users);

        // 2. 遍历所有用户数据，将每个用户的健康数据调用setHealthData进行封装
        for (User user : users) {
            //如果该用户缺乏血压、血糖、血脂数据三者其一，则从users中移除该用户
            if (StringUtils.isEmpty(user.getBloodPressure()) || StringUtils.isEmpty(user.getBloodGlucose()) || StringUtils.isEmpty(user.getBloodFat())) {
                users.remove(user);
                continue;
            }
            System.out.println("用户"+user.getUserOpenid()+",血压:" + user.getBloodPressure());
            Double checkBloodPressure = checkBloodPressure(user.getBloodPressure());
            user.setHealthData("bloodPressure", checkBloodPressure);
            user.setHealthData("bloodFat", Double.valueOf(user.getBloodFat()));
            user.setHealthData("bloodGlucose", Double.valueOf(user.getBloodGlucose()));
        }
        // 3. 找到与该用户健康数据皮尔森系数最高的用户
        // 4. 获取该用户购买的菜单与最近邻的用户购买的菜单进行比较，得到推荐菜单
        Recommend recommend = new Recommend();
        List<Disk> recommendDisk = recommend.recommend(openId, users);
        return recommendDisk;
    }

    public Double checkBloodPressure(String bloodPressure) {
        // 使用正则表达式匹配血压格式
        String regex = "^(\\d{1,3})/(\\d{1,3})$";// 匹配 1-3位数字/1-3位数字
        if (!bloodPressure.matches(regex)) {
            return 0.0;
        }

        // 分割字符串获取收缩压和舒张压
        String[] parts = bloodPressure.split("/");
        int systolic = Integer.parseInt(parts[0]); // 收缩压
        int diastolic = Integer.parseInt(parts[1]); // 舒张压

        // 判断血压范围
        if (systolic < 120 && diastolic < 80) {
            return 1.0;
        } else if (systolic >= 120 && systolic < 130 && diastolic < 80) {
            return 2.0;
        } else if ((systolic >= 130 && systolic < 140) || (diastolic >= 80 && diastolic < 90)) {
            return 3.0;
        } else {
            return 4.0;
        }
    }

    class Recommend {

        /**
         * 在给定用户openid的情况下，计算其他用户和它的距离并排序
         *
         * @param userOpenId
         * @return
         */
        public Map<Double, String> computeNearestNeighbor(String userOpenId, List<User> users) {
            Map<Double, String> distances = new TreeMap<>();

            User u1 = new User(userOpenId);
            for (User user : users) {
                if (userOpenId.equals(user.getUserOpenid())) {
                    u1 = user;
                }
            }

            for (int i = 0; i < users.size(); i++) {
                User u2 = users.get(i);

                if (!u2.getUserOpenid().equals(userOpenId)) {
                    double distance = pearson_dis(u2.getHealthDataList(), u1.getHealthDataList());
                    distances.put(distance, u2.getUserOpenid());
                }

            }
            return distances;
        }


        /**
         * 计算2个健康数据间的pearson距离
         * 选择公式四进行计算
         *
         * @param rating1
         * @param rating2
         * @return
         */
        private double pearson_dis(List<healthData> rating1, List<healthData> rating2) {
            // 获取评分列表的大小
            int n = rating1.size();
            // 提取rating1和rating2中的分数到数组
            double[] rating1Scores = new double[n];
            double[] rating2Scores = new double[n];

            for (int i = 0; i < n; i++) {
                rating1Scores[i] = rating1.get(i).score;
                rating2Scores[i] = rating2.get(i).score;
            }
            // 计算rating1分数的总和
            double Ex = 0.0;
            // 计算rating2分数的总和
            double Ey = 0.0;
            // 计算rating1分数平方的总和
            double Ex2 = 0.0;
            // 计算rating2分数平方的总和
            double Ey2 = 0.0;
            // 计算rating1和rating2分数乘积的总和
            double Exy = 0.0;
            for (int i = 0; i < n; i++) {
                Ex += rating1Scores[i];
                Ey += rating2Scores[i];
                Ex2 += Math.pow(rating1Scores[i], 2);
                Ey2 += Math.pow(rating2Scores[i], 2);
                Exy += rating1Scores[i] * rating2Scores[i];
            }
            // 计算皮尔逊相关系数的分子
            double numerator = Exy - (Ex * Ey / n);
            // 计算皮尔逊相关系数的分母
            double denominator = Math.sqrt((Ex2 - Math.pow(Ex, 2) / n) * (Ey2 - Math.pow(Ey, 2) / n));
            // 如果分母为0，则表示没有相关性，返回0
            if (denominator == 0) return 0.0;
            // 返回皮尔逊相关系数
            return numerator / denominator;
        }


        public List<Disk> recommend(String userOpenId, List<User> users) {
//            Map<Double, String> distances = computeNearestNeighbor(userOpenId, users);
//            System.out.println("最近邻 -> " + distances);
//            //遍历distances，取含最大值的为最近邻
//            String nearest = "";
//            double max = 0.0;
//            for (Map.Entry<Double, String> entry : distances.entrySet()) {
//                if (entry.getKey() > max) {
//                    max = entry.getKey();
//                    nearest = entry.getValue();
//                }
//            }
//            System.out.println("最近邻是 -> " + nearest);

            // 计算最近邻并返回相关性映射
            Map<Double, String> distances = computeNearestNeighbor(userOpenId, users);
            System.out.println("最近邻 -> " + distances);

            // 将距离（相关性）存放到列表中以便排序
            List<Map.Entry<Double, String>> sortedDistances = new ArrayList<>(distances.entrySet());

            // 使用匿名内部类按相关性值从大到小排序
            Collections.sort(sortedDistances, new Comparator<Map.Entry<Double, String>>() {
                public int compare(Map.Entry<Double, String> entry1, Map.Entry<Double, String> entry2) {
                    return Double.compare(entry2.getKey(), entry1.getKey());
                }
            });

            // 输出排序后的结果
            for (Map.Entry<Double, String> entry : sortedDistances) {
                System.out.println("相关性: " + entry.getKey() + ", 用户ID: " + entry.getValue());
            }

            // 选择最相关的用户来进行推荐（如果需要）
            String nearest = sortedDistances.size() > 0 ? sortedDistances.get(0).getValue() : "";
            System.out.println("最相关的用户是 -> " + nearest);



            //找到最近邻吃过，但是我们没看过的菜品，计算推荐
            // 根据userOpenId找到用户吃过的菜品
            List<Disk> neighborRatingsList = userMapper.getDiskByUserOpenId(nearest);
            System.out.println("最近邻吃过的菜品 -> " + neighborRatingsList);

            // 根据userOpenId找到用户吃过的菜品
            List<Disk> userRatingsList = userMapper.getDiskByUserOpenId(userOpenId);
            System.out.println("用户吃过的菜品 -> " + userRatingsList);

            //根据自己和邻居的菜品计算推荐的菜品，遍历邻居的菜品，如果用户吃过的菜品中不包含邻居的菜品，则添加到推荐列表中
            List<Disk> recommendDisks = new ArrayList<>();
            for (Disk neighborDisk : neighborRatingsList) {
                if (!userRatingsList.contains(neighborDisk)) {
                    recommendDisks.add(neighborDisk);
                }
            }
            System.out.println("推荐菜品 -> " + recommendDisks);
            return recommendDisks;
        }
    }

    //护理人员
    @Override
    public Integer loginNursingStaff(String username, String password) {
        Integer loginNursingStaff =userMapper.loginNursingStaff(username,password);
        System.out.println(loginNursingStaff);
        return userMapper.loginNursingStaff(username,password);
    }

    @Override
    public Map<String, String> getNursingStaffInfoByOpenId(String openId){
        User user = userMapper.getNursingStaffInfoByOpenId(openId);
        Map<String,String> userInfo = new HashMap<>();
        userInfo.put("userOpenid",user.getUserOpenid());
        userInfo.put("userName",user.getUserName());
        userInfo.put("userStatus", String.valueOf(user.getUserStatus()));
        userInfo.put("avatarUrl",user.getAvatarUrl());
        return userInfo;
    }



    //查询所有用户
    @Override
    public List<User> getAllUser(String userStatus) {
        return userMapper.selectUser(userStatus);
    }



}




